#include "Globals.h"

#include <cassert>

#include <SDL.h>
#include <SDL_Mixer.h>

#include "utils/UtilsConstants.h"
#include "utils/Error.h"
#include "utils/Timer.h"

#include "MainConstants.h"

#include <graphic\DrawManager.h>
#include <states/GameStates.h>
#include <states/StateManager.h>
#include <utils\CharacterManager.h>
#include <utils\ResourceManager.h>

GameLoop* Globals::gGameLoop = nullptr;
SDL_Window* Globals::gWindow = nullptr;
SDL_Renderer* Globals::gRenderer = nullptr;
Timer Globals::gTimer;
KeyboardState Globals::gKeyboardState;
MouseState Globals::gMouseState;
CollisionManager* Globals::gCollisionManager = nullptr;
ConstantManager* Globals::gConstantManager = nullptr;
DrawManager* Globals::gDrawManager = nullptr;
ResourceManager* Globals::gResourceManager = nullptr;
StateManager* Globals::gStateManager = nullptr;
GameStates* Globals::gGameStates = nullptr;
CharacterManager* Globals::gCharacterManager = nullptr;

bool Globals::init() {
    assert(gWindow == nullptr);
    assert(gRenderer == nullptr);

    // Init SDL
    int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
    if (result != 0) {
        printError("SDL_Init failed");
        return false;
    }

    // Create SDL window
    gWindow = SDL_CreateWindow("Game",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        WINDOW_WIDTH,
        WINDOW_HEIGHT,
        0);
    if (!gWindow) {
        printError("SDL_CreateWindow failed");
        return false;
    }

    // Create rendering context
    gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
    if (!gRenderer) {
        printError("SDL_CreateRenderer failed");
        return false;
    }

    // Set configuration variables
    SDL_SetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION, "1");
    SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");

    // Init SDL_Mixer
    {
        const int audioRate = 22050;
        const uint16_t audioFormat = AUDIO_S16;
        const int audioChannels = 2;
        const int audioBuffers = 4096;

        result = Mix_OpenAudio(audioRate, audioFormat, audioChannels, audioBuffers);
        if (result != 0) {
            printError("Mix_OpenAudio failed");
            return false;
        }

        Mix_Volume(-1 /*all channels*/, MID_VOLUME);
    }

    // Initializes keyboard and mouse states
    gKeyboardState.init();
    gMouseState.init();

	gGameLoop = new GameLoop();
	gConstantManager = new ConstantManager();
	gCollisionManager = new CollisionManager();
	gDrawManager = new DrawManager();
	gResourceManager = new ResourceManager();
    gGameStates = new GameStates();
    gStateManager = new StateManager();
    gStateManager->init();

    // Initialize character manager
    gCharacterManager = new CharacterManager();

    return true;
}

void Globals::destroy() {
    assert(gWindow != nullptr);
    assert(gRenderer != nullptr);

    gKeyboardState.destroy();

    Mix_CloseAudio();

    SDL_DestroyRenderer(gRenderer);
    SDL_DestroyWindow(gWindow);

    delete gCharacterManager;
	delete gConstantManager;
	delete gCollisionManager;
	delete gDrawManager; 
	delete gResourceManager; 
    delete gGameStates;
    delete gStateManager;
	delete gGameLoop;

    atexit(SDL_Quit);
}